import numpy as np
from scipy.ndimage import affine_transform

from dicom_viewer_be_mock_xiaosai.utils.logger import logger
from src.dicom_viewer_be_mock_xiaosai.components.ViewGroupManager import ViewGroupManager
from src.dicom_viewer_be_mock_xiaosai.components import VolumeInfo


def _fast_apply_window(hu_array, window_center, set_window_width, invert):
    # 设置最小窗宽，防止除零错误
    MIN_WINDOW_WIDTH = 0.1
    window_width = max(set_window_width, MIN_WINDOW_WIDTH)
    if invert:
        invert_factor = 0.5  # 可以调整这个值来控制反转程度
        window_center = -window_center * invert_factor
        # 也可以稍微调整窗宽来保持更好的对比度
        window_width = window_width * 2
    min_value = window_center - window_width // 2
    max_value = window_center + window_width // 2
    hu_array = np.clip(hu_array, min_value, max_value)
    normalized = ((hu_array - min_value) / window_width * 255.0)
    return normalized


def _fast_transfer_to_hu(pixel_array, rescale_slope, rescale_intercept):
    return pixel_array * rescale_slope + rescale_intercept


class BaseImgLayer:
    def __init__(self, view_type, dicom_tag_info, volume_info,id_info):
        self.dicom_tag_info = dicom_tag_info
        self.volume_info: VolumeInfo = volume_info
        self.hu_array = None
        self.view_type = view_type
        self.id_info = id_info

    def get_base_img_arr(self, hu_array):
        hu_array = np.asarray(hu_array, dtype=np.float32)
        self.hu_array = hu_array
        window_center, window_width = self.volume_info.view_info[self.view_type].window
        group_config = ViewGroupManager.group_config[self.id_info['group_id']]
        pixel_array = _fast_apply_window(hu_array, window_center, window_width, group_config['invert'])
        transform_pixel_array = self.do_transfer(pixel_array)
        pixel_array_8bit = transform_pixel_array.astype(np.uint8)
        if group_config['invert']:
            return 255 - pixel_array_8bit
        return pixel_array_8bit

    # stack视图大约需要0.01秒。
    def do_transfer(self, pixel_array):
        matrix = self.volume_info.view_info[self.view_type].transform_matrix
        try:
            inverse_matrix = np.linalg.inv(matrix)
        except Exception as e:
            logger.info(f"图像变换 时出错: {e}，原始矩阵为：${matrix}")
            return None
        # # 只需要3x3矩阵的前两行
        affine_matrix = inverse_matrix[:2, :2]

        output_shape = self.volume_info.view_info[self.view_type].render_size
        offset = inverse_matrix[:2, 2]

        # 执行变换
        transformed = affine_transform(
            pixel_array,
            affine_matrix,
            offset=offset,
            output_shape=output_shape,
            order=1
        )
        return transformed

    def get_hu_value_by_position(self, dicom_position):
        # dicom_position的坐标是(y,x)格式,在取值的时候需要[y][x]的方式来取值。
        return self.hu_array[dicom_position[0]][dicom_position[1]]

